/*
问题描述：对于给定的一个表达式，表达式中可以包括常数、算术运行符（包括：“+”、“-”、“*”、“/”、“%”（求余运算）、
“^”（乘幂运算）、“！”（阶乘运算））和括号，编写一个简单计算器，实现表达式的计算。

基本要求：从键盘输入一个正确的表达式，将表达式转换为对应的后缀表达式，并计算后缀表达式的值。对于表达式中的简单错误
（如，除数不能为零、负数无法求阶乘等），能够给出提示，并给出错误信息；表达式中可以包括单个字母表示的变量。

测试数据：任意选取一个符合题目要求的表达式。

提高要求：完成基本要求的基础上，能够支持一部分不规范的表达式（如，3-3+-6），支
持科学计数法表示的数（如，19971400000000表示为：1.99714E13），并具有图形用户界面的简单计算器。

考核要求：
（1）表达式中的数据可以是整数或小数，达到基本要求，成绩为良好。但是，如果仅能处理个位数，成绩为及格；
如果仅能处理整数，成绩为中等。
(2)在达到基本要求的基础之上，完成提高要求，成绩可以为优秀。
*/
#include <iostream> 
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string>
using namespace std;

class Expression
{
	public:
		Expression(string str); //构造函数
        ~Expression( ); //析构函数
        void Compute( ); //计算表达式str的值
        void change();   //将中缀表达式修改为后缀表达式
    private:
        int Comp(char str1, char str2); //比较str1的str2优先级
        string str;
};

Expression :: Expression(string str) //接收键盘输入并加上定界符
{
	this->str = str + "#";
}

Expression :: ~Expression( )
{

}

double Factor(double n)   //求阶乘 
{
	int result=1;
	for(int i=1;i<=n;++i)
	{
		result *=i;
	}
	return result;
}

void Expression :: change()  //转化为后缀表达式 
{
	char character[100];   //用于存放后缀表达式中的字符 
	character[0] = '#'; //栈character初始化为定界符
	char Unkown='0';
	int a2=0;   //初始化栈character的栈顶指针
	
	char ex[100];   //定义字符串数组用于存放转换后的数字串 
	ex[0]='$';
	int i,j=0;
	
	for (i = 0; str[i] != '\0'; ) //依次扫描每一个字符
	{
		while(str[i] >= 48 && str[i] <= 57||str[i] == '.'||str[i] == 'E'||str[i] == 'e') //数字0的ASCII码是48或是小数点(46) 
    	{
    	    ex[j]=str[i];
    	    i++;
    	    j++;
    	    ex[j]='\0';   //为了标识末尾，好判断数组ex已到末尾 ,一定要写j，若是j+1就会多出一位，使得数字有残余 
    	}
    	if(str[i]>='a'&&str[i]<='z'||str[i]>='A'&&str[i]<='Z')
    	{
    		Unkown=str[i];
    		i++;
    	}
    	if(ex[0]!='$')
    	{
    		double digital=atof(ex);
    		j=0;
    		ex[0]='$';
    		if(Unkown!='0')   //有未知量字母 
    		{
    			cout<<digital<<Unkown<<' ';
    		} 
    		else
			{
				cout<<digital<<' ';
			}
    	}
    	else if(str[i]=='^'||str[i]=='!'||str[i]=='*'||str[i]=='/'||str[i]=='+'||str[i]=='-'||str[i]=='%'||str[i]=='#')
    	{
    		int k = Comp(str[i], character[a2]);
    		if (k == 1) //str[i]的优先级高
            {
            	character[++a2]=str[i++]; //将str[i]压入运算符栈
            }
            else if (k == -1) //str[i]的优先级低
            {
            	while(Comp(str[i], character[a2])==-1)
            	{
            		cout<<character[a2]<<' ';   //输出顶端的操作符 
            		character[a2--];   //导出顶端操作符 
            	}
            	character[++a2]=str[i++];
            }
    	}
    	else if(str[i]=='(')    //扫描到左括号的情况 
    	{
    		character[++a2]=str[i++]; //将str[i]压入运算符栈
    	}
    	else if(str[i]==')')   //扫描到右括号的情况 
    	{
    		while(character[a2]!='(')   //判断目前栈顶元素是否为左括号 
            {
            	cout<<character[a2]<<' ';   //输出顶端的操作符 
            	character[a2--];   //导出顶端操作符 
            }
            character[a2--];   //将左括号移除
			i++;   //继续扫描下一个 
        }
	}
	cout<<endl;
}
void Expression :: Compute( )
{
	double OPND[100];   //存数字 
	char OPTR[100];   //存运算符 //定义两个顺序栈
	
	char Unkown='0';   //未知参数初始化为0 
	
	char ex[100];   //定义字符串数组用于存放转换后的数字串 
	ex[0]='$';
	
    OPTR[0] = '#'; //栈OPTR初始化为定界符
    int top1 = -1, top2 = 0; //初始化栈OPND和OPTR的栈顶指针
    int i, k, op, j=0;
    double x,y,z;

    for (i = 0; str[i] != '\0'; ) //依次扫描每一个字符
    {  
    	while (str[i] >= 48 && str[i] <= 57||str[i] == '.'||str[i] == 'E'||str[i] == 'e') //数字0的ASCII码是48或是小数点(46) 
    	{
    	    ex[j]=str[i];
    	    i++;
    	    j++;
    	    ex[j]='\0';   //为了标识末尾，好判断数组ex已到末尾 ,一定要写j，若是j+1就会多出一位，使得数字有残余 
    	}
    	if(ex[0]!='$')
    	{
    		OPND[++top1]=atof(ex);
    		j=0;
    		ex[0]='$';
    	}
    	else if(str[i]>='a'&&str[i]<='z'||str[i]>='A'&&str[i]<='Z')   //判断表达式中是否含有未知量字母 (条件必须按此形式写不然报错)
    	{
    		Unkown=str[i];
			i++;   //继续扫描下一个 
    	}
    	else if(str[i] == '!')   //单独计算阶乘 
    	{
    		if(x>=0)
    		{
    			x = OPND[top1--]; //从运算对象栈出栈一个元素
    			z=Factor(x);   //求阶乘的函数 
				OPND[++top1] = z; //运算结果入运算对象栈
				
				i++;
    		}
            else
            {
            	cout<<"您的表达式中出现了负数！";
            	cout<<"负数没有阶乘，这么低级的错误都犯？！";
            }
    	}
        else   //剩下的运算符情况 
        {
        	k = Comp(str[i], OPTR[top2]);
            if (k == 1) //str[i]的优先级高
            {
            	OPTR[++top2] =str[i++]; //将str[i]压入运算符栈
            }
            else if (k == -1) //str[i]的优先级低
            {
            	y = OPND[top1--]; //从运算对象栈出栈两个元素
                x = OPND[top1--];
                op = OPTR[top2--]; //从运算符栈出栈一个元素

                switch (op) // op为运算符，进行相应运算
                {
                	case '+': z = x + y; break;
                    case '-': z = x - y; break;
                    case '*': z = x * y; break;
 					case '/':
 						if(y!=0)
 						{
 							z = x / y;
 						}
 						else
 						{
 							cout<<"除数不能为零，这么低级的错误都犯？！";
 						}
					  break;
 					case '%': z = fmod(x,y); break;
 					case '^':
 						z = 1;
					 for(int i=0;i<y;i++)
					 {
					 	z = z * x;
					 } 
					 break;
					default: break;
				}
				OPND[++top1] = z; //运算结果入运算对象栈
			}
			else
			{ //str[i]与运算符栈的栈顶元素优先级相同
				top2--; //匹配str[i]，扫描下一个字符
				i++;
			}
		}
	}
//	return OPND[top1];
	if(Unkown!='0')   //表达式中有字符 
	{
		if(OPND[top1]==0)   //但最终结果为0，则直接输出0
		{
			cout<<OPND[top1]<<endl;
		}
		else
		{
			cout<<OPND[top1]<<Unkown<<endl;
		}
	}
	else   //表达式中没有字符 
	{
		cout<< OPND[top1]<<endl; //运算对象栈的栈顶元素即为运算结果
	} 
}

int Expression :: Comp(char str1, char str2)
{ //比较str1和str2的优先级，1：str1高；0：相同；-1：str1低
	switch (str1)
	{
		case '+': case '-': if (str2 == '(' || str2 == '#') return 1; else return -1;
		break;
		case '*': case '/':case '%' :if (str2 == '('||str2 == '#'||str2 == '+'||str2 == '-') return 1; else return -1;
		break;
		case '^':case '!':if(str2 == '^'||str2 == '!') return -1; else return 1;
		case '(': return 1; break;
		case ')': if (str2 == '(') return 0; else return -1;
		break;
		case '#': if (str2 == '#') return 0; else return -1;
		break;
		default: break;
	}
}

int main( )
{
	string str;
	int count=0;
	while(1)
	{
		cout << "请输入一个表达式：" << endl;
	    cin >> str; 
	    
	    
		Expression E{str}; //定义对象变量E
		
	/*	double result = E.Compute( ); //result保存计算结果
		cout<<result<<endl;*/
	
		cout << "表达式的值是："<< endl;   //方法直接输出结果
		E.Compute( );   //方法直接输出结果
		
		cout<<"其后缀表达式为："<<endl; 
		E.change();  //调用输出后缀表达式的方法 
		
/*		if(result>=1000||result<1)   //大于1000和小于1的结果都要进行科学计数法 
		{
			if(result>=1000)   //大于1000的结果进行科学计数法 
			{
				double a=result;
				while(a>=10)
				{
					a=a/10;
					count++;
				} 
				cout<< "表达式的值是："<<a<<'E'<<count<<endl;
			}
			else if(result<1)   //小于1的结果进行科学计数法 
			{
				double a=result;
				while(a<1)
				{
					a=a*10;
					count++;
				}
				cout<< "表达式的值是："<<a<<'E'<<'-'<<count<<endl;
			}
		}
		else   //其他正常的数字直接输出 
		{
			cout << "表达式的值是：" << result << endl;
		} 
	}*/
	}
	return 0;
}
